package com.gitee.wsl.ext.net

import java.net.*

/**
 * Checks if [NetworkInterface] has IPv4/IPv6 address that can communicate with the network
 */
fun NetworkInterface.isAvailableInterface(): Boolean =
    isConnectedToNetwork() && (hasV4Address() || hasV6Address())

/**
 * Checks if [NetworkInterface] has IPv4 address that can communicate with the network
 */
fun NetworkInterface.isAvailableV4Interface(): Boolean =
    isConnectedToNetwork() && hasV4Address()

/**
 * Checks if [NetworkInterface] has IPv6 address that can communicate with the network
 */
fun NetworkInterface.isAvailableV6Interface(): Boolean =
    isConnectedToNetwork() && hasV6Address()

/**
 * Checks if [NetworkInterface] has address that can communicate with the network
 */
private fun NetworkInterface.isConnectedToNetwork(): Boolean = try {
    !isLoopback && isUp && supportsMulticast()
} catch (_: SocketException) {
    false
}

/**
 * Checks if [NetworkInterface] has IPv4 address
 */
private fun NetworkInterface.hasV4Address(): Boolean = interfaceAddresses
    .any { it.address is Inet4Address }

/**
 * Checks if [NetworkInterface] has IPv6 address
 */
private fun NetworkInterface.hasV6Address(): Boolean =
    interfaceAddresses.any { it.address is Inet6Address }


/**
 * Extract IPv4 address from assigned to the interface.
 *
 * @receiver NetworkInterface
 * @return InterfaceAddress
 * @throws IllegalArgumentException receiver does not have IPv4 address
 */
// VisibleForTesting
 fun NetworkInterface.findInet4Address(): InterfaceAddress =
    interfaceAddresses.find { it.address.isAvailableInet4Address() }
        ?: throw IllegalArgumentException("$this does not have IPv4 address.")

/**
 * Extract IPv6 address from assigned to the interface
 *
 * @receiver NetworkInterface
 * @return InterfaceAddress
 * @throws IllegalArgumentException receiver does not have IPv6 address
 */
// VisibleForTesting
 fun NetworkInterface.findInet6Address(): InterfaceAddress =
    interfaceAddresses.find { it.address.isAvailableInet6Address() }
        ?: throw IllegalArgumentException("$this does not have IPv6 address.")
